class GPrinter {
  EscCommand before;
  List<EscCommand> list;
  EscCommand end;

  GPrinter(this.before, this.list, this.end);

  Map<String, dynamic> toJson() {
    Map<String, dynamic> data = <String, dynamic>{
      "before": before.toJson(),
      "end": end.toJson(),
    };

    List<Map<String, dynamic>> items = [];
    for (var value in list) {
      items.add(value.toJson());
    }
    data["list"] = items;
    return data;
  }
}

class TextCommand extends EscCommand {
  int type = 1;
  CharacterSize? characterSize; //字体大小
  UnderlineMode? underlineMode; //非汉字下划线
  UnderlineMode? kanjiUnderLine; //汉字下划线
  bool? printAndLineFeed;
  int? printAndFeedLines;
  SelectJustification? selectJustification; // 对齐方式
  int? absolutePrintPosition; //绝对位置
  List<String> contents;

  TextCommand(this.contents, {
    this.characterSize,
    this.underlineMode,
    this.kanjiUnderLine,
    this.selectJustification,
    this.absolutePrintPosition,
    this.printAndLineFeed,
    this.printAndFeedLines,
  });

  Map<String, dynamic> toJson() {
    Map<String, dynamic> data = <String, dynamic>{};

    data["type"] = 1;
    data["contents"] = contents;
    if (characterSize != null) {
      data["characterSize"] = {
        "width": characterSize?.width.value,
        "height": characterSize?.height.value,
      };
    }
    if (underlineMode != null) {
      data["underlineMode"] = underlineMode?.value;
    }

    if (kanjiUnderLine != null) {
      data["kanjiUnderLine"] = kanjiUnderLine?.value;
    }
    if (selectJustification != null) {
      data["selectJustification"] = selectJustification?.value;
    }
    data["printAndLineFeed"] = printAndLineFeed;
    data["printAndFeedLines"] = printAndFeedLines;
    return data;
  }
}

class QrcodeCommand extends EscCommand {
  int type = 2;
  String content;
  int? selectErrorCorrectionLevel;
  int? selectSizeOfModuleForQRCode;
  SelectJustification? selectJustification; // 对齐方式

  QrcodeCommand(this.content, {
    this.selectErrorCorrectionLevel,
    this.selectSizeOfModuleForQRCode,
  });

  Map<String, dynamic> toJson() {
    Map<String, dynamic> data = <String, dynamic>{};
    data["type"] = 2;
    data["content"] = content;
    data["selectErrorCorrectionLevel"] = selectErrorCorrectionLevel;
    data["selectSizeOfModuleForQRCode"] = selectSizeOfModuleForQRCode;
    data["selectJustification"] = selectJustification?.value;
    data["printAndLineFeed"] = printAndLineFeed;
    data["printAndFeedLines"] = printAndFeedLines;
    return data;
  }
}

class ImageCommand extends EscCommand{

}

class BarcodeCommand extends EscCommand {
  int type = 3;
  BarCodeSelectPrintingPosition? selectPrintingPosition;
  int? barcodeHeight;
  int? barcodeWidth;
  String content;

  BarcodeCommand(
  this.content, {
  this.selectPrintingPosition,
  this.barcodeHeight,
  this.barcodeWidth,
  });
}

class EscCommand {
  bool? initializePrinter;
  bool? cutPaper;
  bool? printAndLineFeed;
  int? printAndFeedLines;

  EscCommand({
    this.printAndLineFeed,
    this.initializePrinter,
    this.cutPaper,
    this.printAndFeedLines,
  });

  Map<String, dynamic> toJson() =>
      {
        "type": 0,
        "printAndLineFeed": printAndLineFeed,
        "initializePrinter": initializePrinter,
        "cutPaper": cutPaper,
        "printAndFeedLines": printAndFeedLines
      };
}

class CharacterSize {
  WidthZoom width;
  HeightZoom height;

  CharacterSize(this.width, this.height);
}

enum WidthZoom {
  MUL_1(0),
  MUL_2(1),
  MUL_3(2),
  MUL_4(3),
  MUL_5(4),
  MUL_6(5),
  MUL_7(6),
  MUL_8(7);

  const WidthZoom(this.value);

  final int value;
}

enum HeightZoom {
  MUL_1(0),
  MUL_2(1),
  MUL_3(2),
  MUL_4(3),
  MUL_5(4),
  MUL_6(5),
  MUL_7(6),
  MUL_8(7);

  const HeightZoom(this.value);

  final int value;
}

enum UnderlineMode {
  OFF(0),
  UNDERLINE_1DOT(1),
  UNDERLINE_2DOT(2);

  const UnderlineMode(this.value);

  final int value;
}

enum SelectJustification {
  LEFT(0),
  CENTER(1),
  RIGHT(2);

  const SelectJustification(this.value);

  final int value;
}

enum BarCodeSelectPrintingPosition {
  NO_PRINT(0),
  ABOVE(1),
  BELOW(2),
  ABOVE_AND_BELOW(3);

  const BarCodeSelectPrintingPosition(this.value);

  final int value;
}
